package com.uniflow.config;

import com.uniflow.common.Result;
import com.uniflow.common.ResultCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * 全局异常处理器
 * 统一处理系统异常，返回标准化的错误响应
 * 
 * @author uniflow
 * @since 1.0.0
 */
@RestControllerAdvice
public class GlobalExceptionHandler {
    
    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
    
    /**
     * 处理参数验证异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<Result<Object>> handleMethodArgumentNotValidException(
            MethodArgumentNotValidException e, HttpServletRequest request) {
        
        logger.warn("参数验证失败: {}", e.getMessage());
        
        List<String> errors = new ArrayList<>();
        for (FieldError error : e.getBindingResult().getFieldErrors()) {
            errors.add(error.getField() + ": " + error.getDefaultMessage());
        }
        
        Result<Object> result = Result.error(ResultCode.PARAM_ERROR, "参数验证失败: " + String.join(", ", errors));
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(result);
    }
    
    /**
     * 处理绑定异常
     */
    @ExceptionHandler(BindException.class)
    public ResponseEntity<Result<Object>> handleBindException(
            BindException e, HttpServletRequest request) {
        
        logger.warn("参数绑定失败: {}", e.getMessage());
        
        List<String> errors = new ArrayList<>();
        for (FieldError error : e.getBindingResult().getFieldErrors()) {
            errors.add(error.getField() + ": " + error.getDefaultMessage());
        }
        
        Result<Object> result = Result.error(ResultCode.PARAM_ERROR, "参数绑定失败: " + String.join(", ", errors));
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(result);
    }
    
    /**
     * 处理约束违反异常
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public ResponseEntity<Result<Object>> handleConstraintViolationException(
            ConstraintViolationException e, HttpServletRequest request) {
        
        logger.warn("约束验证失败: {}", e.getMessage());
        
        List<String> errors = new ArrayList<>();
        Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
        for (ConstraintViolation<?> violation : violations) {
            errors.add(violation.getPropertyPath() + ": " + violation.getMessage());
        }
        
        Result<Object> result = Result.error(ResultCode.PARAM_ERROR, "约束验证失败: " + String.join(", ", errors));
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(result);
    }
    
    /**
     * 处理参数类型不匹配异常
     */
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public ResponseEntity<Result<Object>> handleMethodArgumentTypeMismatchException(
            MethodArgumentTypeMismatchException e, HttpServletRequest request) {
        
        logger.warn("参数类型不匹配: {}", e.getMessage());
        
        String message = String.format("参数 '%s' 类型不正确，期望类型: %s", 
                e.getName(), e.getRequiredType().getSimpleName());
        
        Result<Object> result = Result.error(ResultCode.PARAM_INVALID, message);
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(result);
    }
    
    /**
     * 处理访问拒绝异常
     */
    @ExceptionHandler(AccessDeniedException.class)
    public ResponseEntity<Result<Object>> handleAccessDeniedException(
            AccessDeniedException e, HttpServletRequest request) {
        
        logger.warn("访问被拒绝: {} - {}", request.getRequestURI(), e.getMessage());
        
        Result<Object> result = Result.error(ResultCode.FORBIDDEN, "权限不足，访问被拒绝");
        return ResponseEntity.status(HttpStatus.FORBIDDEN).body(result);
    }
    
    /**
     * 处理404异常
     */
    @ExceptionHandler(NoHandlerFoundException.class)
    public ResponseEntity<Result<Object>> handleNoHandlerFoundException(
            NoHandlerFoundException e, HttpServletRequest request) {
        
        logger.warn("接口不存在: {} {}", e.getHttpMethod(), e.getRequestURL());
        
        Result<Object> result = Result.error(ResultCode.NOT_FOUND, "接口不存在: " + e.getRequestURL());
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(result);
    }
    
    /**
     * 处理非法参数异常
     */
    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity<Result<Object>> handleIllegalArgumentException(
            IllegalArgumentException e, HttpServletRequest request) {
        
        logger.warn("非法参数: {}", e.getMessage());
        
        Result<Object> result = Result.error(ResultCode.PARAM_INVALID, "参数错误: " + e.getMessage());
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(result);
    }
    
    /**
     * 处理运行时异常
     */
    @ExceptionHandler(RuntimeException.class)
    public ResponseEntity<Result<Object>> handleRuntimeException(
            RuntimeException e, HttpServletRequest request) {
        
        logger.error("运行时异常: {} - {}", request.getRequestURI(), e.getMessage(), e);
        
        Result<Object> result = Result.error(ResultCode.ERROR, "系统内部错误: " + e.getMessage());
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result);
    }
    
    /**
     * 处理通用异常
     */
    @ExceptionHandler(Exception.class)
    public ResponseEntity<Result<Object>> handleException(
            Exception e, HttpServletRequest request) {
        
        logger.error("系统异常: {} - {}", request.getRequestURI(), e.getMessage(), e);
        
        Result<Object> result = Result.error(ResultCode.ERROR, "系统异常，请联系管理员");
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result);
    }
}